﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Encoder.cs" company="Microsoft Corporation">
//   Copyright (c) 2008, 2009, 2010 All Rights Reserved, Microsoft Corporation
//
//   This source is subject to the Microsoft Permissive License.
//   Please see the License.txt file for more information.
//   All other rights reserved.
//
//   THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//   KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//   IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//   PARTICULAR PURPOSE.
//
// </copyright>
// <summary>
//   Performs encoding of input strings to provide protection against
//   Cross-Site Scripting (XSS) attacks and LDAP injection attacks in
//   various contexts.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.Web;

namespace Nasa8x.Core
{
    /// <summary>
    /// Performs encoding of input strings to provide protection against
    /// Cross-Site Scripting (XSS) attacks and LDAP injection attacks in 
    /// various contexts.
    /// </summary>
    /// <remarks>
    /// This encoding library uses the Principle of Inclusions, 
    /// sometimes referred to as "safe-listing" to provide protection 
    /// against injection attacks.  With safe-listing protection, 
    /// algorithms look for valid inputs and automatically treat 
    /// everything outside that set as a potential attack.  This library 
    /// can be used as a defense in depth approach with other mitigation 
    /// techniques. It is suitable for applications with high security 
    /// requirements.
    /// </remarks>
    public static class Encoder
    {
        /// <summary>
        /// Empty string for Visual Basic Script contextes
        /// </summary>
        private const string VbScriptEmptyString = "\"\"";

        /// <summary>
        /// Empty string for Java Script contextes
        /// </summary>
        private const string JavaScriptEmptyString = "''";

        /// <summary>
        /// Initializes character Html encoding array
        /// </summary>
        private static readonly char[][] SafeListCodes = InitializeSafeList();

        /// <summary>
        /// Intialises the HTML special rules.
        /// </summary>
        private static readonly char[][] HtmlSpecialRules = InitalizeHtmlSpecialRules();

        /// <summary>
        /// Intialises the XML special rules.
        /// </summary>
        private static readonly char[][] XmlSpecialRules = InitalizeXmlSpecialRules();

        /// <summary>
        /// Encodes input strings used in Lightweight Directory Access Protocol (LDAP) search queries.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>Encoded string for use in LDAP search queries.</returns>
        /// <remarks>This method encodes all but known safe characters defined in the safe list.
        /// <newpara/>
        /// RFC 4515 defines the format in which special characters need to be 
        /// escaped to be used inside a search filter. Special characters need to be 
        /// encoded in \XX format where XX is the hex representation of the character.
        /// <newpara/>
        /// The following examples illustrate the use of the escaping mechanism.
        /// <list type="table">
        /// <item><term>(o=Parens R Us (for all your parenthetical needs))</term><description>(o=Parens R Us \28for all your parenthetical needs\29)</description></item>
        /// <item><term>(cn=***)</term><description>(cn=*\2A*)</description></item>
        /// <item><term>(filename=C:\MyFile)</term><description>(filename=C:\5cMyFile)</description></item>
        /// <item><term>(bin=NULLNULLNULLEOT)</term><description>(bin=\00\00\00\04)</description></item>
        /// <item><term>(sn=Lučić)</term><description>(sn=Lu\c4\8di\c4\87)</description></item>
        /// </list>
        /// </remarks>
        public static string LdapEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Set initial values
            int outputLength = 0;
            int inputLength = input.Length;
            Encoding inputEncoding;

            // Use a new char array, reserving 8 bytes for each unicode character  
            var encodedInput = new char[inputLength*24];

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];
                string currentCharacterAsString = input[i].ToString();

                // Escape values from the safe list and escaping SPACE, PERIOD and COMMA
                if ((SafeListCodes[currentCharacterAsInteger] != null) ||
                    (currentCharacterAsInteger == 32) ||
                    (currentCharacterAsInteger == 44) ||
                    (currentCharacterAsInteger == 46))
                {
                    // Character needs to be encoded to default UTF-8 as per RFC 1514
                    inputEncoding = Encoding.UTF8;
                    byte[] inputEncodingBytes = inputEncoding.GetBytes(currentCharacterAsString);
                    int noinputEncodingBytes = inputEncodingBytes.Length;
                    for (int index = 0; index < noinputEncodingBytes; index++)
                    {
                        var ch = (char) inputEncodingBytes[index];

                        // Character code is invalid.
                        if (ch > 256)
                        {
                            continue;
                        }

                        encodedInput[outputLength++] = '\\';
                        string hex = ((int) ch).ToString("x", CultureInfo.InvariantCulture).PadLeft(2, '0');
                        encodedInput[outputLength++] = hex[0];
                        encodedInput[outputLength++] = hex[1];
                    }
                }
                else
                {
                    // Character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings used in Cascading Style Sheet (CSS) elements.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>Encoded string for use in CSS elements.</returns>
        /// <remarks>This method encodes all but known safe characters defined in the safe list.
        /// <newpara/>
        /// The CSS character escape sequence consists of a backslash character (\) followed by 
        /// between one and six hexadecimal digits that represent a character code from the 
        /// ISO 10646 standard (which is equivalent to Unicode, for all intents and purposes). Any 
        /// character other than a hexadecimal digit will terminate the escape sequence. If a 
        /// character following the escape sequence is also a valid hexadecimal digit then it must 
        /// either include six digits in the escape, or use a whitespace character to terminate the 
        /// escape.
        /// Ex: \000041 denotes A and \000020 denotes a space.
        /// </remarks>
        public static string CssEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Setup default values.
            int outputLength = 0;
            int inputLength = input.Length;
            Encoding inputEncoding;

            // Create a new character array.
            var encodedInput = new char[inputLength*24];

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInput = input[i];
                string currentCharacterAsString = input[i].ToString();

                // Escape characters and also escape SPACE, PERIOD and COMMA
                if ((SafeListCodes[currentCharacterAsInput] != null) ||
                    (currentCharacterAsInput == 32) ||
                    (currentCharacterAsInput == 44) ||
                    (currentCharacterAsInput == 46))
                {
                    // Character needs to be encoded to default UTF-16
                    inputEncoding = Encoding.BigEndianUnicode;
                    encodedInput[outputLength++] = '\\';
                    byte[] inputEncodingBytes = inputEncoding.GetBytes(currentCharacterAsString);
                    int noinputEncodingBytes = inputEncodingBytes.Length;
                    for (int index = 0; index < noinputEncodingBytes; index++)
                    {
                        var ch = (char) inputEncodingBytes[index];

                        // Invalid character value.
                        if (ch > 256)
                        {
                            continue;
                        }

                        string hex = ((int) ch).ToString("x", CultureInfo.InvariantCulture).PadLeft(2, '0');
                        encodedInput[outputLength++] = hex[0];
                        encodedInput[outputLength++] = hex[1];
                    }
                }
                else
                {
                    // character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings for use in HTML.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in HTML.
        /// </returns>
        /// <remarks>
        /// This function encodes all characters which are not on its safe list  Characters are encoded using the HTML4.0 named entity values or, if
        /// they do not have a named entity, using &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and their related encoded outputs:
        /// <list type="table">
        /// <item><term>&lt;script&gt;alert('XSS Attack!');&lt;/script&gt;</term><description>&amp;lt;script&amp;gt;alert('XSS Attack!');&amp;lt;/script&amp;gt;</description></item>
        /// <item><term>user@contoso.com</term><description>user@contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross Site Scripting Library</description></item>
        /// <item><term>"Anti-Cross Site Scripting Library"</term><description>&amp;quote;Anti-Cross Site Scripting Library>&amp;quote;</description></item>
        /// </list>
        /// </remarks>
        public static string HtmlEncode(string input)
        {
            return HtmlEncode(input, false);
        }

        /// <summary>
        /// Encodes input strings for use in HTML.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <param name="useNamedEntities">Value indicating if the HTML 4.0 named entities should be used.</param>
        /// <returns>
        /// Encoded string for use in HTML.
        /// </returns>
        /// <remarks>
        /// This function encodes all characters which are not on its safe list  Characters are encoded using the HTML4.0 named entity values or, if
        /// they do not have a named entity, using &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and their related encoded outputs:
        /// <list type="table">
        /// <item><term>&lt;script&gt;alert('XSS Attack!');&lt;/script&gt;</term><description>&amp;lt;script&amp;gt;alert('XSS Attack!');&amp;lt;/script&amp;gt;</description></item>
        /// <item><term>user@contoso.com</term><description>user@contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross Site Scripting Library</description></item>
        /// <item><term>"Anti-Cross Site Scripting Library"</term><description>&amp;quote;Anti-Cross Site Scripting Library>&amp;quote;</description></item>
        /// </list>
        /// </remarks>
        public static string HtmlEncode(string input, bool useNamedEntities)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Setup a new character array for output.
            int outputLength = 0;
            int inputLength = input.Length;
            var encodedInput = new char[inputLength*10];
            // Worse case scenario - the longest entity name, thetasym is 10 characters, including the & and ;.

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];

                if ((currentCharacterAsInteger <= '>' && HtmlSpecialRules[currentCharacterAsInteger] != null) ||
                    (useNamedEntities && HtmlSpecialRules[currentCharacterAsInteger] != null))
                {
                    char[] encodedCharacter = HtmlSpecialRules[currentCharacterAsInteger];
                    encodedInput[outputLength++] = '&';
                    for (int j = 0; j < encodedCharacter.Length; j++)
                    {
                        encodedInput[outputLength++] = encodedCharacter[j];
                    }

                    encodedInput[outputLength++] = ';';
                }
                else if (SafeListCodes[currentCharacterAsInteger] != null)
                {
                    // character needs to be encoded
                    char[] encodedCharacter = SafeListCodes[currentCharacterAsInteger];
                    encodedInput[outputLength++] = '&';
                    encodedInput[outputLength++] = '#';
                    for (int j = 0; j < encodedCharacter.Length; j++)
                    {
                        encodedInput[outputLength++] = encodedCharacter[j];
                    }

                    encodedInput[outputLength++] = ';';
                }
                else
                {
                    // character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes an input string and embeds it in a colored &lt;SPAN&gt; tag for use in HTML.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <param name="clr">KnownColor like System.Drawing.KnownColor.CadetBlue</param>
        /// <returns>
        ///  The encoded string is embebded within a &lt;SPAN&gt; tag and style settings for use in HTML.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description><div style='background-color : #ffffff'>alert&#40;&apos;XSS Attack&#33;&apos;&#41;&#59;</div></description></item>
        /// <item><term>user@contoso.com</term><description>user&#64;contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross Site Scripting Library</description></item>
        /// </list>
        /// </remarks>
        public static string HtmlEncode(string input, KnownColor clr)
        {
            // HTMLEncode will handle the encoding
            // This check is for making sure that bgcolor is required or not.
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Request.QueryString["MarkAntiXssOutput"] != null)
                {
                    string returnInput = "<span name='#markantixssoutput' style ='background-color : " +
                                         Color.FromKnownColor(clr).Name + "'>" + HtmlEncode(input) + "</span>";
                    return returnInput;
                }
            }

            return HtmlEncode(input);
        }

        /// <summary>
        /// Encodes input strings for use in HTML attributes.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in HTML attributes.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using  &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>alert&#40;&#39;XSS&#32;Attack&#33;&#39;&#41;&#59;</description></item>
        /// <item><term>user@contoso.com</term><description>user&#64;contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross&#32;Site&#32;Scripting&#32;Library</description></item>
        /// </list>
        /// </remarks>
        public static string HtmlAttributeEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Use a new char array.
            int outputLength = 0;
            int inputLength = input.Length;
            var encodedInput = new char[inputLength*9]; // worst case length scenario

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];

                // Check encoding and also encode spaces
                if ((SafeListCodes[currentCharacterAsInteger] != null) || (currentCharacterAsInteger == 32))
                {
                    // character needs to be encoded
                    char[] thisChar = SafeListCodes[currentCharacterAsInteger];

                    encodedInput[outputLength++] = '&';
                    encodedInput[outputLength++] = '#';
                    if (currentCharacterAsInteger == 32)
                    {
                        encodedInput[outputLength++] = '3';
                        encodedInput[outputLength++] = '2';
                    }
                    else
                    {
                        for (int j = 0; j < thisChar.Length; j++)
                        {
                            encodedInput[outputLength++] = thisChar[j];
                        }
                    }

                    encodedInput[outputLength++] = ';';
                }
                else
                {
                    // character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings for use in universal resource locators (URLs).
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in URLs.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using %SINGLE_BYTE_HEX 
        /// and %uDOUBLE_BYTE_HEX notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>alert%28%27XSS%20Attack%21%27%29%3b</description></item>
        /// <item><term>user@contoso.com</term><description>user%40contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross%20Site%20Scripting%20Library</description></item>
        /// </list>
        /// </remarks>
        [SuppressMessage(
            "Microsoft.Design",
            "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "As this is meant as a replace for HttpUility.Encode we must keep the same return ttype.")]
        public static string UrlEncode(string input)
        {
            return UrlEncode(input, Encoding.UTF8);
        }

        /// <summary>
        /// Encodes input strings for use in universal resource locators (URLs).
        /// </summary>
        /// <param name="input">Input string</param>
        /// <param name="codePage">Codepage number of the input</param>
        /// <returns>
        /// Encoded string for use in URLs.
        /// </returns>
        /// <remarks>
        /// This function encodes the output as per the encoding parameter (codepage) passed to it. It encodes 
        /// all but known safe characters.  Characters are encoded using %SINGLE_BYTE_HEX and %DOUBLE_BYTE_HEX notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSSあAttack!');</term><description>alert%28%27XSS%82%a0Attack%21%27%29%3b</description></item>
        /// <item><term>user@contoso.com</term><description>user%40contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross%20Site%20Scripting%20Library</description></item>
        /// </list>
        /// </remarks>
        [SuppressMessage(
            "Microsoft.Design",
            "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "As this is meant as a replace for HttpUility.Encode we must keep the same return ttype.")]
        public static string UrlEncode(string input, int codePage)
        {
            return UrlEncode(input, Encoding.GetEncoding(codePage));
        }

        /// <summary>
        /// Encodes input strings for use in universal resource locators (URLs).
        /// </summary>
        /// <param name="input">Input string</param>
        /// <param name="inputEncoding">Input encoding type</param>
        /// <returns>
        /// Encoded string for use in URLs.
        /// </returns>
        /// <remarks>
        /// This function encodes the output as per the encoding parameter (codepage) passed to it. It encodes 
        /// all but known safe characters.  Characters are encoded using %SINGLE_BYTE_HEX and %DOUBLE_BYTE_HEX notation.
        /// If the inputEncoding is null then UTF-8 is assumed by default.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSSあAttack!');</term><description>alert%28%27XSS%82%a0Attack%21%27%29%3b</description></item>
        /// <item><term>user@contoso.com</term><description>user%40contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross%20Site%20Scripting%20Library</description></item>
        /// </list>
        /// </remarks>
        [SuppressMessage(
            "Microsoft.Design",
            "CA1055:UriReturnValuesShouldNotBeStrings",
            Justification = "As this is meant as a replace for HttpUility.Encode we must keep the same return ttype.")]
        public static string UrlEncode(string input, Encoding inputEncoding)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Assuming the default to be UTF-8
            if (inputEncoding == null)
            {
                inputEncoding = Encoding.UTF8;
            }

            int outputLength = 0;
            int inputLength = input.Length;

            // Use a new char array.
            var encodedInput = new char[inputLength*24]; // worst case length scenario            

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];
                string currentCharacterAsString = input[i].ToString();

                // Check safe list and also include spaces and commands
                if ((SafeListCodes[currentCharacterAsInteger] != null) ||
                    (currentCharacterAsInteger == 32) ||
                    (currentCharacterAsInteger == 43) ||
                    (currentCharacterAsInteger == 44) ||
                    (currentCharacterAsInteger == 63))
                {
                    byte[] inputEncodingBytes = inputEncoding.GetBytes(currentCharacterAsString);
                    int noinputEncodingBytes = inputEncodingBytes.Length;
                    for (int index = 0; index < noinputEncodingBytes; index++)
                    {
                        var ch = (char) inputEncodingBytes[index];

                        // Check for invalid character.
                        if (ch > 256)
                        {
                            continue;
                        }

                        encodedInput[outputLength++] = '%';
                        string hex = ((int) ch).ToString("x", CultureInfo.InvariantCulture).PadLeft(2, '0');
                        encodedInput[outputLength++] = hex[0];
                        encodedInput[outputLength++] = hex[1];
                    }
                }
                else
                {
                    // character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings for use in XML.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in XML.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters. Characters are encoded using &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>alert&#40;&#39;XSS Attack&#33;&#39;&#41;&#59;</description></item>
        /// <item><term>user@contoso.com</term><description>user&#64;contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross Site Scripting Library</description></item>
        /// </list>
        /// </remarks>
        public static string XmlEncode(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return string.Empty;
            }

            // Setup a new character array for output.
            int outputLength = 0;
            int inputLength = input.Length;
            var encodedInput = new char[inputLength*8];

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];

                if (currentCharacterAsInteger <= '>' && XmlSpecialRules[currentCharacterAsInteger] != null)
                {
                    char[] encodedCharacter = XmlSpecialRules[currentCharacterAsInteger];
                    encodedInput[outputLength++] = '&';
                    for (int j = 0; j < encodedCharacter.Length; j++)
                    {
                        encodedInput[outputLength++] = encodedCharacter[j];
                    }

                    encodedInput[outputLength++] = ';';
                }
                else if (SafeListCodes[currentCharacterAsInteger] != null)
                {
                    // character needs to be encoded
                    char[] encodedCharacter = SafeListCodes[currentCharacterAsInteger];
                    encodedInput[outputLength++] = '&';
                    encodedInput[outputLength++] = '#';
                    for (int j = 0; j < encodedCharacter.Length; j++)
                    {
                        encodedInput[outputLength++] = encodedCharacter[j];
                    }

                    encodedInput[outputLength++] = ';';
                }
                else
                {
                    // character does not need encoding
                    encodedInput[outputLength++] = input[i];
                }
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings for use in XML attributes.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in XML attributes.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using &amp;#DECIMAL; notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>alert&#40;&#39;XSS&#32;Attack&#33;&#39;&#41;&#59;</description></item>
        /// <item><term>user@contoso.com</term><description>user&#64;contoso.com</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>Anti-Cross&#32;Site&#32;Scripting&#32;Library</description></item>
        /// </list>
        /// </remarks>
        public static string XmlAttributeEncode(string input)
        {
            // HtmlEncodeAttribute will handle input
            return HtmlAttributeEncode(input);
        }

        /// <summary>
        /// Encodes input strings for use in JavaScript.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in JavaScript.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using \xSINGLE_BYTE_HEX and \uDOUBLE_BYTE_HEX notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>'alert\x28\x27XSS Attack\x21\x27\x29\x3b'</description></item>
        /// <item><term>user@contoso.com</term><description>'user\x40contoso.com'</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>'Anti-Cross Site Scripting Library'</description></item>
        /// </list>
        /// </remarks>
        public static string JavaScriptEncode(string input)
        {
            return JavaScriptEncode(input, true);
        }

        /// <summary>
        /// Encodes input strings for use in JavaScript.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <param name="emitQuotes">value indicating whether or not to emit quotes. true = emit quote. false = no quote.</param>
        /// <returns>
        /// Encoded string for use in JavaScript and does not return the output with en quotes.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are encoded using \xSINGLE_BYTE_HEX and \uDOUBLE_BYTE_HEX notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// <item><term> </term><description>Other International character ranges</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>'alert\x28\x27XSS Attack\x21\x27\x29\x3b'</description></item>
        /// <item><term>user@contoso.com</term><description>'user\x40contoso.com'</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>'Anti-Cross Site Scripting Library'</description></item>
        /// </list>
        /// </remarks>
        public static string JavaScriptEncode(string input, bool emitQuotes)
        {
            // Input validation: empty or null string condition
            if (string.IsNullOrEmpty(input))
            {
                return emitQuotes ? JavaScriptEmptyString : string.Empty;
            }

            // Use a new char array.
            int outputLength = 0;
            int inputLength = input.Length;
            var returnMe = new char[inputLength*8]; // worst case length scenario

            // First step is to start the encoding with an apostrophe if flag is true.
            if (emitQuotes)
            {
                returnMe[outputLength++] = '\'';
            }

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];
                char currentCharacter = input[i];
                if (SafeListCodes[currentCharacterAsInteger] != null || currentCharacterAsInteger == 92 ||
                    (currentCharacterAsInteger >= 123 && currentCharacterAsInteger <= 127))
                {
                    // character needs to be encoded
                    if (currentCharacterAsInteger >= 127)
                    {
                        returnMe[outputLength++] = '\\';
                        returnMe[outputLength++] = 'u';
                        string hex = ((int) currentCharacter).ToString("x", CultureInfo.InvariantCulture).PadLeft(4, '0');
                        returnMe[outputLength++] = hex[0];
                        returnMe[outputLength++] = hex[1];
                        returnMe[outputLength++] = hex[2];
                        returnMe[outputLength++] = hex[3];
                    }
                    else
                    {
                        returnMe[outputLength++] = '\\';
                        returnMe[outputLength++] = 'x';
                        string hex = ((int) currentCharacter).ToString("x", CultureInfo.InvariantCulture).PadLeft(2, '0');
                        returnMe[outputLength++] = hex[0];
                        returnMe[outputLength++] = hex[1];
                    }
                }
                else
                {
                    // character does not need encoding
                    returnMe[outputLength++] = input[i];
                }
            }

            // Last step is to end the encoding with an apostrophe if flag is true.
            if (emitQuotes)
            {
                returnMe[outputLength++] = '\'';
            }

            return new string(returnMe, 0, outputLength);
        }

        /// <summary>
        /// Encodes input strings for use in Visual Basic Script.
        /// </summary>
        /// <param name="input">String to be encoded</param>
        /// <returns>
        /// Encoded string for use in Visual Basic Script.
        /// </returns>
        /// <remarks>
        /// This function encodes all but known safe characters.  Characters are 
        /// encoded using &#38;chrw(DECIMAL) notation.
        /// <newpara/>
        /// Safe characters include:
        /// <list type="table">
        /// <item><term>a-z</term><description>Lower case alphabet</description></item>
        /// <item><term>A-Z</term><description>Upper case alphabet</description></item>
        /// <item><term>0-9</term><description>Numbers</description></item>
        /// <item><term>,</term><description>Comma</description></item>
        /// <item><term>.</term><description>Period</description></item>
        /// <item><term>-</term><description>Dash</description></item>
        /// <item><term>_</term><description>Underscore</description></item>
        /// <item><term> </term><description>Space</description></item>
        /// </list>
        /// <newpara/>
        /// Example inputs and encoded outputs:
        /// <list type="table">
        /// <item><term>alert('XSS Attack!');</term><description>"alert"&#38;chrw(40)&#38;chrw(39)&#38;"XSS Attack"&#38;chrw(33)&#38;chrw(39)&#38;chrw(41)&#38;chrw(59)</description></item>
        /// <item><term>user@contoso.com</term><description>"user"&#38;chrw(64)&#38;"contoso.com"</description></item>
        /// <item><term>Anti-Cross Site Scripting Library</term><description>"Anti-Cross Site Scripting Library"</description></item>
        /// </list></remarks>
        public static string VisualBasicScriptEncode(string input)
        {
            // Input validation: empty or null string condition
            if (string.IsNullOrEmpty(input))
            {
                return VbScriptEmptyString;
            }

            // Use a new char array.
            int outputLength = 0;
            int inputLength = input.Length;
            var encodedInput = new char[inputLength*12]; // worst case length scenario

            // flag to surround double quotes around safe characters
            bool isInQuotes = false;

            for (int i = 0; i < inputLength; i++)
            {
                int currentCharacterAsInteger = input[i];
                char currentCharacter = input[i];
                if (SafeListCodes[currentCharacterAsInteger] != null)
                {
                    // character needs to be encoded

                    // surround in quotes
                    if (isInQuotes)
                    {
                        // get out of quotes
                        encodedInput[outputLength++] = '"';
                        isInQuotes = false;
                    }

                    // adding "encoded" characters
                    string temp = "&chrw(" + ((uint) currentCharacter) + ")";
                    foreach (char ch in temp)
                    {
                        encodedInput[outputLength++] = ch;
                    }
                }
                else
                {
                    // character does not need encoding
                    // surround in quotes
                    if (!isInQuotes)
                    {
                        // add quotes to start
                        encodedInput[outputLength++] = '&';
                        encodedInput[outputLength++] = '"';
                        isInQuotes = true;
                    }

                    encodedInput[outputLength++] = input[i];
                }
            }

            // if we're inside of quotes, close them
            if (isInQuotes)
            {
                encodedInput[outputLength++] = '"';
            }

            // finally strip extraneous "&" from beginning of the string, if necessary and RETURN
            if (encodedInput.Length > 0 && encodedInput[0] == '&')
            {
                return new string(encodedInput, 1, outputLength - 1);
            }

            return new string(encodedInput, 0, outputLength);
        }

        /// <summary>
        /// Initializes the safe list.
        /// </summary>
        /// <returns>A two dimensional character array containing characters and their encoded values.</returns>
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity",
            Justification = "This is necessary complexity.")]
        private static char[][] InitializeSafeList()
        {
            // TODO : Move to T4 template and generate.
            var allCharacters = new char[65536][];
            for (int i = 0; i < allCharacters.Length; i++)
            {
                if (
                    (i >= 97 && i <= 122) || // a-z
                    (i >= 65 && i <= 90) || // A-Z
                    (i >= 48 && i <= 57) || // 0-9
                    i == 32 || // space
                    i == 46 || // .
                    i == 44 || // ,
                    i == 45 || // -
                    i == 95 || // _
                    (i >= 256 && i <= 591) || // Latin,Extended-A,Latin Extended-B        
                    (i >= 880 && i <= 2047) ||
                    // Greek and Coptic,Cyrillic,Cyrillic Supplement,Armenian,Hebrew,Arabic,Syriac,Arabic,Supplement,Thaana,NKo
                    (i >= 2304 && i <= 6319) ||
                    // Devanagari,Bengali,Gurmukhi,Gujarati,Oriya,Tamil,Telugu,Kannada,Malayalam,Sinhala,Thai,Lao,Tibetan,Myanmar,eorgian,Hangul Jamo,Ethiopic,Ethiopic Supplement,Cherokee,Unified Canadian Aboriginal Syllabics,Ogham,Runic,Tagalog,Hanunoo,Buhid,Tagbanwa,Khmer,Mongolian   
                    (i >= 6400 && i <= 6687) || // Limbu, Tai Le, New Tai Lue, Khmer, Symbols, Buginese
                    (i >= 6912 && i <= 7039) || // Balinese         
                    (i >= 7680 && i <= 8191) || // Latin Extended Additional, Greek Extended        
                    (i >= 11264 && i <= 11743) ||
                    // Glagolitic, Latin Extended-C, Coptic, Georgian Supplement, Tifinagh, Ethiopic Extended    
                    (i >= 12352 && i <= 12591) || // Hiragana, Katakana, Bopomofo       
                    (i >= 12688 && i <= 12735) || // Kanbun, Bopomofo Extended        
                    (i >= 12784 && i <= 12799) || // Katakana, Phonetic Extensions         
                    (i >= 19968 && i <= 40899) || // Mixed japanese/chinese/korean
                    (i >= 40960 && i <= 42191) || // Yi Syllables, Yi Radicals        
                    (i >= 42784 && i <= 43055) || // Latin Extended-D, Syloti, Nagri        
                    (i >= 43072 && i <= 43135) || // Phags-pa         
                    (i >= 44032 && i <= 55215) /* Hangul Syllables */)
                {
                    allCharacters[i] = null;
                }
                else
                {
                    string integerStringValue = i.ToString(CultureInfo.InvariantCulture);
                    int integerStringLength = integerStringValue.Length;
                    var thisChar = new char[integerStringLength];
                    for (int j = 0; j < integerStringLength; j++)
                    {
                        thisChar[j] = integerStringValue[j];
                    }

                    allCharacters[i] = thisChar;
                }
            }

            return allCharacters;
        }

        /// <summary>
        /// Initializes the special rules for HTML named entitites.
        /// </summary>
        /// <returns>A two dimensional jagged character array containing html special characters and their encoded named entity values.</returns>
        [SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode",
            Justification = "Will be moved to T4 code generation in a couple of iterations.")]
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity",
            Justification = "This is necessary complexity.")]
        private static char[][] InitalizeHtmlSpecialRules()
        {
            // TODO : Move to T4 template and generate.
            var allCharacters = new char[65536][];
            for (int i = 0; i < allCharacters.Length; i++)
            {
                switch (i)
                {
                    case '"':
                        allCharacters[i] = "quote".ToCharArray();
                        break;
                    case '&':
                        allCharacters[i] = "amp".ToCharArray();
                        break;
                    case '<':
                        allCharacters[i] = "lt".ToCharArray();
                        break;
                    case '>':
                        allCharacters[i] = "gt".ToCharArray();
                        break;
                    case 160:
                        allCharacters[i] = "nbsp".ToCharArray();
                        break;
                    case 161:
                        allCharacters[i] = "iexcl".ToCharArray();
                        break;
                    case 162:
                        allCharacters[i] = "cent".ToCharArray();
                        break;
                    case 163:
                        allCharacters[i] = "pound".ToCharArray();
                        break;
                    case 164:
                        allCharacters[i] = "curren".ToCharArray();
                        break;
                    case 165:
                        allCharacters[i] = "yen".ToCharArray();
                        break;
                    case 166:
                        allCharacters[i] = "brvbar".ToCharArray();
                        break;
                    case 167:
                        allCharacters[i] = "sect".ToCharArray();
                        break;
                    case 168:
                        allCharacters[i] = "uml".ToCharArray();
                        break;
                    case 169:
                        allCharacters[i] = "copy".ToCharArray();
                        break;
                    case 170:
                        allCharacters[i] = "ordf".ToCharArray();
                        break;
                    case 171:
                        allCharacters[i] = "laquo".ToCharArray();
                        break;
                    case 172:
                        allCharacters[i] = "not".ToCharArray();
                        break;
                    case 173:
                        allCharacters[i] = "shy".ToCharArray();
                        break;
                    case 174:
                        allCharacters[i] = "reg".ToCharArray();
                        break;
                    case 175:
                        allCharacters[i] = "macr".ToCharArray();
                        break;
                    case 176:
                        allCharacters[i] = "deg".ToCharArray();
                        break;
                    case 177:
                        allCharacters[i] = "plusmn".ToCharArray();
                        break;
                    case 178:
                        allCharacters[i] = "sup2".ToCharArray();
                        break;
                    case 179:
                        allCharacters[i] = "sup3".ToCharArray();
                        break;
                    case 180:
                        allCharacters[i] = "acute".ToCharArray();
                        break;
                    case 181:
                        allCharacters[i] = "micro".ToCharArray();
                        break;
                    case 182:
                        allCharacters[i] = "para".ToCharArray();
                        break;
                    case 183:
                        allCharacters[i] = "middot".ToCharArray();
                        break;
                    case 184:
                        allCharacters[i] = "cedil".ToCharArray();
                        break;
                    case 185:
                        allCharacters[i] = "sup1".ToCharArray();
                        break;
                    case 186:
                        allCharacters[i] = "ordm".ToCharArray();
                        break;
                    case 187:
                        allCharacters[i] = "raduo".ToCharArray();
                        break;
                    case 188:
                        allCharacters[i] = "frac14".ToCharArray();
                        break;
                    case 189:
                        allCharacters[i] = "frac12".ToCharArray();
                        break;
                    case 190:
                        allCharacters[i] = "frac34".ToCharArray();
                        break;
                    case 191:
                        allCharacters[i] = "iquest".ToCharArray();
                        break;
                    case 192:
                        allCharacters[i] = "Agrave".ToCharArray();
                        break;
                    case 193:
                        allCharacters[i] = "Aacute".ToCharArray();
                        break;
                    case 194:
                        allCharacters[i] = "Acirc".ToCharArray();
                        break;
                    case 195:
                        allCharacters[i] = "Atilde".ToCharArray();
                        break;
                    case 196:
                        allCharacters[i] = "Auml".ToCharArray();
                        break;
                    case 197:
                        allCharacters[i] = "Aring".ToCharArray();
                        break;
                    case 198:
                        allCharacters[i] = "AElig".ToCharArray();
                        break;
                    case 199:
                        allCharacters[i] = "Ccedil".ToCharArray();
                        break;
                    case 200:
                        allCharacters[i] = "Egrave".ToCharArray();
                        break;
                    case 201:
                        allCharacters[i] = "Eacute".ToCharArray();
                        break;
                    case 202:
                        allCharacters[i] = "Ecirc".ToCharArray();
                        break;
                    case 203:
                        allCharacters[i] = "Euml".ToCharArray();
                        break;
                    case 204:
                        allCharacters[i] = "Igrave".ToCharArray();
                        break;
                    case 205:
                        allCharacters[i] = "Iacute".ToCharArray();
                        break;
                    case 206:
                        allCharacters[i] = "Icirc".ToCharArray();
                        break;
                    case 207:
                        allCharacters[i] = "Iuml".ToCharArray();
                        break;
                    case 208:
                        allCharacters[i] = "ETH".ToCharArray();
                        break;
                    case 209:
                        allCharacters[i] = "Ntilde".ToCharArray();
                        break;
                    case 210:
                        allCharacters[i] = "Ograve".ToCharArray();
                        break;
                    case 211:
                        allCharacters[i] = "Oacute".ToCharArray();
                        break;
                    case 212:
                        allCharacters[i] = "Ocirc".ToCharArray();
                        break;
                    case 213:
                        allCharacters[i] = "Otilde".ToCharArray();
                        break;
                    case 214:
                        allCharacters[i] = "Ouml".ToCharArray();
                        break;
                    case 215:
                        allCharacters[i] = "times".ToCharArray();
                        break;
                    case 216:
                        allCharacters[i] = "Oslash".ToCharArray();
                        break;
                    case 217:
                        allCharacters[i] = "Ugrave".ToCharArray();
                        break;
                    case 218:
                        allCharacters[i] = "Uacute".ToCharArray();
                        break;
                    case 219:
                        allCharacters[i] = "UCirc".ToCharArray();
                        break;
                    case 220:
                        allCharacters[i] = "UUml".ToCharArray();
                        break;
                    case 221:
                        allCharacters[i] = "Yacute".ToCharArray();
                        break;
                    case 222:
                        allCharacters[i] = "THORN".ToCharArray();
                        break;
                    case 223:
                        allCharacters[i] = "szlig".ToCharArray();
                        break;
                    case 224:
                        allCharacters[i] = "agrave".ToCharArray();
                        break;
                    case 225:
                        allCharacters[i] = "aacute".ToCharArray();
                        break;
                    case 226:
                        allCharacters[i] = "acirc".ToCharArray();
                        break;
                    case 227:
                        allCharacters[i] = "atilde".ToCharArray();
                        break;
                    case 228:
                        allCharacters[i] = "auml".ToCharArray();
                        break;
                    case 229:
                        allCharacters[i] = "aring".ToCharArray();
                        break;
                    case 230:
                        allCharacters[i] = "aelig".ToCharArray();
                        break;
                    case 231:
                        allCharacters[i] = "ccedil".ToCharArray();
                        break;
                    case 232:
                        allCharacters[i] = "egrave".ToCharArray();
                        break;
                    case 233:
                        allCharacters[i] = "eacute".ToCharArray();
                        break;
                    case 234:
                        allCharacters[i] = "ecirc".ToCharArray();
                        break;
                    case 235:
                        allCharacters[i] = "euml".ToCharArray();
                        break;
                    case 236:
                        allCharacters[i] = "igrave".ToCharArray();
                        break;
                    case 237:
                        allCharacters[i] = "iacute".ToCharArray();
                        break;
                    case 238:
                        allCharacters[i] = "icirc".ToCharArray();
                        break;
                    case 239:
                        allCharacters[i] = "iuml".ToCharArray();
                        break;
                    case 240:
                        allCharacters[i] = "eth".ToCharArray();
                        break;
                    case 241:
                        allCharacters[i] = "ntilde".ToCharArray();
                        break;
                    case 242:
                        allCharacters[i] = "ograve".ToCharArray();
                        break;
                    case 243:
                        allCharacters[i] = "oacute".ToCharArray();
                        break;
                    case 244:
                        allCharacters[i] = "ocirc".ToCharArray();
                        break;
                    case 245:
                        allCharacters[i] = "otilde".ToCharArray();
                        break;
                    case 246:
                        allCharacters[i] = "ouml".ToCharArray();
                        break;
                    case 247:
                        allCharacters[i] = "divide".ToCharArray();
                        break;
                    case 248:
                        allCharacters[i] = "oslash".ToCharArray();
                        break;
                    case 249:
                        allCharacters[i] = "ugrave".ToCharArray();
                        break;
                    case 250:
                        allCharacters[i] = "uacute".ToCharArray();
                        break;
                    case 251:
                        allCharacters[i] = "ucirc".ToCharArray();
                        break;
                    case 252:
                        allCharacters[i] = "uuml".ToCharArray();
                        break;
                    case 253:
                        allCharacters[i] = "yacute".ToCharArray();
                        break;
                    case 254:
                        allCharacters[i] = "thorn".ToCharArray();
                        break;
                    case 255:
                        allCharacters[i] = "yuml".ToCharArray();
                        break;
                    case 338:
                        allCharacters[i] = "OElig".ToCharArray();
                        break;
                    case 339:
                        allCharacters[i] = "oelig".ToCharArray();
                        break;
                    case 352:
                        allCharacters[i] = "Scaron".ToCharArray();
                        break;
                    case 353:
                        allCharacters[i] = "scaron".ToCharArray();
                        break;
                    case 376:
                        allCharacters[i] = "Yuml".ToCharArray();
                        break;
                    case 402:
                        allCharacters[i] = "fnof".ToCharArray();
                        break;
                    case 710:
                        allCharacters[i] = "circ".ToCharArray();
                        break;
                    case 732:
                        allCharacters[i] = "tilde".ToCharArray();
                        break;
                    case 913:
                        allCharacters[i] = "Alpha".ToCharArray();
                        break;
                    case 914:
                        allCharacters[i] = "Beta".ToCharArray();
                        break;
                    case 915:
                        allCharacters[i] = "Gamma".ToCharArray();
                        break;
                    case 916:
                        allCharacters[i] = "Delta".ToCharArray();
                        break;
                    case 917:
                        allCharacters[i] = "Epsilon".ToCharArray();
                        break;
                    case 918:
                        allCharacters[i] = "Zeta".ToCharArray();
                        break;
                    case 919:
                        allCharacters[i] = "Eta".ToCharArray();
                        break;
                    case 920:
                        allCharacters[i] = "Theta".ToCharArray();
                        break;
                    case 921:
                        allCharacters[i] = "Iota".ToCharArray();
                        break;
                    case 922:
                        allCharacters[i] = "Kappa".ToCharArray();
                        break;
                    case 923:
                        allCharacters[i] = "Lambda".ToCharArray();
                        break;
                    case 924:
                        allCharacters[i] = "Mu".ToCharArray();
                        break;
                    case 925:
                        allCharacters[i] = "Nu".ToCharArray();
                        break;
                    case 927:
                        allCharacters[i] = "Xi".ToCharArray();
                        break;
                    case 928:
                        allCharacters[i] = "Omicron".ToCharArray();
                        break;
                    case 929:
                        allCharacters[i] = "Pi".ToCharArray();
                        break;
                    case 930:
                        allCharacters[i] = "Rho".ToCharArray();
                        break;
                    case 931:
                        allCharacters[i] = "Sigma".ToCharArray();
                        break;
                    case 932:
                        allCharacters[i] = "Tau".ToCharArray();
                        break;
                    case 933:
                        allCharacters[i] = "Upsilon".ToCharArray();
                        break;
                    case 934:
                        allCharacters[i] = "Phi".ToCharArray();
                        break;
                    case 935:
                        allCharacters[i] = "Chi".ToCharArray();
                        break;
                    case 936:
                        allCharacters[i] = "Psi".ToCharArray();
                        break;
                    case 937:
                        allCharacters[i] = "Omega".ToCharArray();
                        break;
                    case 945:
                        allCharacters[i] = "alpha".ToCharArray();
                        break;
                    case 946:
                        allCharacters[i] = "beta".ToCharArray();
                        break;
                    case 947:
                        allCharacters[i] = "gamma".ToCharArray();
                        break;
                    case 948:
                        allCharacters[i] = "delta".ToCharArray();
                        break;
                    case 949:
                        allCharacters[i] = "epsilon".ToCharArray();
                        break;
                    case 950:
                        allCharacters[i] = "zeta".ToCharArray();
                        break;
                    case 951:
                        allCharacters[i] = "eta".ToCharArray();
                        break;
                    case 952:
                        allCharacters[i] = "theta".ToCharArray();
                        break;
                    case 953:
                        allCharacters[i] = "iota".ToCharArray();
                        break;
                    case 954:
                        allCharacters[i] = "kappa".ToCharArray();
                        break;
                    case 955:
                        allCharacters[i] = "lambda".ToCharArray();
                        break;
                    case 956:
                        allCharacters[i] = "mu".ToCharArray();
                        break;
                    case 957:
                        allCharacters[i] = "nu".ToCharArray();
                        break;
                    case 958:
                        allCharacters[i] = "xi".ToCharArray();
                        break;
                    case 959:
                        allCharacters[i] = "omicron".ToCharArray();
                        break;
                    case 960:
                        allCharacters[i] = "pi".ToCharArray();
                        break;
                    case 961:
                        allCharacters[i] = "rho".ToCharArray();
                        break;
                    case 962:
                        allCharacters[i] = "sigmaf".ToCharArray();
                        break;
                    case 963:
                        allCharacters[i] = "sigma".ToCharArray();
                        break;
                    case 964:
                        allCharacters[i] = "tau".ToCharArray();
                        break;
                    case 965:
                        allCharacters[i] = "upsilon".ToCharArray();
                        break;
                    case 966:
                        allCharacters[i] = "phi".ToCharArray();
                        break;
                    case 967:
                        allCharacters[i] = "chi".ToCharArray();
                        break;
                    case 968:
                        allCharacters[i] = "psi".ToCharArray();
                        break;
                    case 969:
                        allCharacters[i] = "omega".ToCharArray();
                        break;
                    case 977:
                        allCharacters[i] = "thetasym".ToCharArray();
                        break;
                    case 978:
                        allCharacters[i] = "upsih".ToCharArray();
                        break;
                    case 982:
                        allCharacters[i] = "piv".ToCharArray();
                        break;
                    case 0x2002:
                        allCharacters[i] = "ensp".ToCharArray();
                        break;
                    case 0x2003:
                        allCharacters[i] = "emsp".ToCharArray();
                        break;
                    case 0x2009:
                        allCharacters[i] = "thinsp".ToCharArray();
                        break;
                    case 0x200C:
                        allCharacters[i] = "zwnj".ToCharArray();
                        break;
                    case 0x200D:
                        allCharacters[i] = "zwj".ToCharArray();
                        break;
                    case 0x200E:
                        allCharacters[i] = "lrm".ToCharArray();
                        break;
                    case 0x200F:
                        allCharacters[i] = "rlm".ToCharArray();
                        break;
                    case 0x2013:
                        allCharacters[i] = "ndash".ToCharArray();
                        break;
                    case 0x2014:
                        allCharacters[i] = "mdash".ToCharArray();
                        break;
                    case 0x2018:
                        allCharacters[i] = "lsquo".ToCharArray();
                        break;
                    case 0x2019:
                        allCharacters[i] = "rsquo".ToCharArray();
                        break;
                    case 0x201A:
                        allCharacters[i] = "sbquo".ToCharArray();
                        break;
                    case 0x201C:
                        allCharacters[i] = "ldquo".ToCharArray();
                        break;
                    case 0x201D:
                        allCharacters[i] = "rdquo".ToCharArray();
                        break;
                    case 0x201E:
                        allCharacters[i] = "bdquo".ToCharArray();
                        break;
                    case 0x2020:
                        allCharacters[i] = "dagger".ToCharArray();
                        break;
                    case 0x2021:
                        allCharacters[i] = "Dagger".ToCharArray();
                        break;
                    case 0x2022:
                        allCharacters[i] = "bull".ToCharArray();
                        break;
                    case 0x2026:
                        allCharacters[i] = "hellip".ToCharArray();
                        break;
                    case 0x2030:
                        allCharacters[i] = "permil".ToCharArray();
                        break;
                    case 0x2032:
                        allCharacters[i] = "prime".ToCharArray();
                        break;
                    case 0x2023:
                        allCharacters[i] = "Prime".ToCharArray();
                        break;
                    case 0x2039:
                        allCharacters[i] = "lsaquo".ToCharArray();
                        break;
                    case 0x203A:
                        allCharacters[i] = "rsaquo".ToCharArray();
                        break;
                    case 0x203E:
                        allCharacters[i] = "oline".ToCharArray();
                        break;
                    case 0x2044:
                        allCharacters[i] = "frasl".ToCharArray();
                        break;
                    case 0x20AC:
                        allCharacters[i] = "euro".ToCharArray();
                        break;
                    case 0x2111:
                        allCharacters[i] = "image".ToCharArray();
                        break;
                    case 0x2118:
                        allCharacters[i] = "weierp".ToCharArray();
                        break;
                    case 0x211C:
                        allCharacters[i] = "real".ToCharArray();
                        break;
                    case 0x2122:
                        allCharacters[i] = "trade".ToCharArray();
                        break;
                    case 0x2135:
                        allCharacters[i] = "alefsym".ToCharArray();
                        break;
                    case 0x2190:
                        allCharacters[i] = "larr".ToCharArray();
                        break;
                    case 0x2191:
                        allCharacters[i] = "uarr".ToCharArray();
                        break;
                    case 0x2192:
                        allCharacters[i] = "rarr".ToCharArray();
                        break;
                    case 0x2193:
                        allCharacters[i] = "darr".ToCharArray();
                        break;
                    case 0x2194:
                        allCharacters[i] = "harr".ToCharArray();
                        break;
                    case 0x2195:
                        allCharacters[i] = "crarr".ToCharArray();
                        break;
                    case 0x21D0:
                        allCharacters[i] = "lArr".ToCharArray();
                        break;
                    case 0x21D1:
                        allCharacters[i] = "uArr".ToCharArray();
                        break;
                    case 0x21D2:
                        allCharacters[i] = "rArr".ToCharArray();
                        break;
                    case 0x21D3:
                        allCharacters[i] = "dArr".ToCharArray();
                        break;
                    case 0x21D4:
                        allCharacters[i] = "hArr".ToCharArray();
                        break;
                    case 0x2200:
                        allCharacters[i] = "forall".ToCharArray();
                        break;
                    case 0x2202:
                        allCharacters[i] = "part".ToCharArray();
                        break;
                    case 0x2203:
                        allCharacters[i] = "exist".ToCharArray();
                        break;
                    case 0x2205:
                        allCharacters[i] = "empty".ToCharArray();
                        break;
                    case 0x2207:
                        allCharacters[i] = "nabla".ToCharArray();
                        break;
                    case 0x2208:
                        allCharacters[i] = "isin".ToCharArray();
                        break;
                    case 0x2209:
                        allCharacters[i] = "notin".ToCharArray();
                        break;
                    case 0x220B:
                        allCharacters[i] = "ni".ToCharArray();
                        break;
                    case 0x220F:
                        allCharacters[i] = "prod".ToCharArray();
                        break;
                    case 0x2211:
                        allCharacters[i] = "sum".ToCharArray();
                        break;
                    case 0x2212:
                        allCharacters[i] = "minus".ToCharArray();
                        break;
                    case 0x2217:
                        allCharacters[i] = "lowast".ToCharArray();
                        break;
                    case 0x221A:
                        allCharacters[i] = "radic".ToCharArray();
                        break;
                    case 0x221D:
                        allCharacters[i] = "prop".ToCharArray();
                        break;
                    case 0x221E:
                        allCharacters[i] = "infin".ToCharArray();
                        break;
                    case 0x2220:
                        allCharacters[i] = "ang".ToCharArray();
                        break;
                    case 0x2227:
                        allCharacters[i] = "and".ToCharArray();
                        break;
                    case 0x2228:
                        allCharacters[i] = "or".ToCharArray();
                        break;
                    case 0x2229:
                        allCharacters[i] = "cap".ToCharArray();
                        break;
                    case 0x222A:
                        allCharacters[i] = "cup".ToCharArray();
                        break;
                    case 0x222B:
                        allCharacters[i] = "int".ToCharArray();
                        break;
                    case 0x2234:
                        allCharacters[i] = "there4".ToCharArray();
                        break;
                    case 0x223C:
                        allCharacters[i] = "sim".ToCharArray();
                        break;
                    case 0x2245:
                        allCharacters[i] = "cong".ToCharArray();
                        break;
                    case 0x2248:
                        allCharacters[i] = "asymp".ToCharArray();
                        break;
                    case 0x2260:
                        allCharacters[i] = "ne".ToCharArray();
                        break;
                    case 0x2261:
                        allCharacters[i] = "equiv".ToCharArray();
                        break;
                    case 0x2264:
                        allCharacters[i] = "le".ToCharArray();
                        break;
                    case 0x2265:
                        allCharacters[i] = "ge".ToCharArray();
                        break;
                    case 0x2282:
                        allCharacters[i] = "sub".ToCharArray();
                        break;
                    case 0x2283:
                        allCharacters[i] = "sup".ToCharArray();
                        break;
                    case 0x2284:
                        allCharacters[i] = "nsub".ToCharArray();
                        break;
                    case 0x2286:
                        allCharacters[i] = "sube".ToCharArray();
                        break;
                    case 0x2287:
                        allCharacters[i] = "supe".ToCharArray();
                        break;
                    case 0x2295:
                        allCharacters[i] = "oplus".ToCharArray();
                        break;
                    case 0x2297:
                        allCharacters[i] = "otimes".ToCharArray();
                        break;
                    case 0x22A5:
                        allCharacters[i] = "perp".ToCharArray();
                        break;
                    case 0x22C5:
                        allCharacters[i] = "sdot".ToCharArray();
                        break;
                    case 0x2308:
                        allCharacters[i] = "lceil".ToCharArray();
                        break;
                    case 0x2309:
                        allCharacters[i] = "rceil".ToCharArray();
                        break;
                    case 0x230A:
                        allCharacters[i] = "lfloor".ToCharArray();
                        break;
                    case 0x230B:
                        allCharacters[i] = "rfloor".ToCharArray();
                        break;
                    case 0x2329:
                        allCharacters[i] = "lang".ToCharArray();
                        break;
                    case 0x232A:
                        allCharacters[i] = "rlang".ToCharArray();
                        break;
                    case 0x25CA:
                        allCharacters[i] = "loz".ToCharArray();
                        break;
                    case 0x2660:
                        allCharacters[i] = "spades".ToCharArray();
                        break;
                    case 0x2663:
                        allCharacters[i] = "clubs".ToCharArray();
                        break;
                    case 0x2665:
                        allCharacters[i] = "hearts".ToCharArray();
                        break;
                    case 0x2666:
                        allCharacters[i] = "diams".ToCharArray();
                        break;
                    default:
                        allCharacters[i] = null;
                        break;
                }
            }

            return allCharacters;
        }

        /// <summary>
        /// Initializes the special rules for XML named entitites.
        /// </summary>
        /// <returns>A two dimensional jagged character array containing xml special characters and their encoded named entity values.</returns>
        private static char[][] InitalizeXmlSpecialRules()
        {
            var allCharacters = new char['>' + 1][];
            for (int i = 0; i <= '>'; i++)
            {
                switch (i)
                {
                    case '"':
                        allCharacters[i] = "quote".ToCharArray();
                        break;
                    case '&':
                        allCharacters[i] = "amp".ToCharArray();
                        break;
                    case '\'':
                        allCharacters[i] = "apos".ToCharArray();
                        break;
                    case '<':
                        allCharacters[i] = "lt".ToCharArray();
                        break;
                    case '>':
                        allCharacters[i] = "gt".ToCharArray();
                        break;
                }
            }

            return allCharacters;
        }
    }
}